package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.common.constant.HttpStatus;
import com.zzyl.common.core.page.TableDataInfo;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.nursing.domain.CheckIn;
import com.zzyl.nursing.domain.Reservation;
import com.zzyl.nursing.dto.ReservationDto;
import com.zzyl.nursing.dto.ReservationPageDto;
import com.zzyl.nursing.mapper.MemberReservationMapper;
import com.zzyl.nursing.service.ICheckInService;
import com.zzyl.nursing.service.IMemberReservationService;
import com.zzyl.nursing.vo.MemberReservationCountByTimeVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class MemberReservationServiceImpl extends ServiceImpl<MemberReservationMapper, Reservation> implements IMemberReservationService {
    @Autowired
    private MemberReservationMapper memberReservationMapper;
    @Autowired
    private ICheckInService checkInService;

    /**
     * 统计取消预约次数
     *
     * @return
     */
    @Override
    public Integer cancelledCount() {
        Long userId = UserThreadLocal.getUserId();
        long time = System.currentTimeMillis();
        LocalDateTime ldt = LocalDateTimeUtil.of(time);
        LocalDateTime startTime = ldt.toLocalDate().atStartOfDay();
        LocalDateTime endTime = startTime.plusDays(1);
        return memberReservationMapper.cancelledCount(userId, startTime, endTime);
    }

    /**
     * 统计预约时间段内预约次数
     *
     * @param time
     * @return
     */
    @Override
    public List<Map<String, Integer>> countByTime(Long time) {
        //将Long类型时间戳转化为 LocalDateTime
        LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault());
        LocalDateTime startTime = ldt.toLocalDate().atStartOfDay();
        LocalDateTime endTime = startTime.plusDays(1);
        List<Map<String, Integer>> list = memberReservationMapper.countByTime(startTime, endTime);
        return list;
    }

    /**
     * 新增预约
     *
     * @param reservationDto
     */
    @Override
    public void add(ReservationDto reservationDto) {
        Reservation reservation = new Reservation();
        if (ObjectUtil.isEmpty(reservationDto)) {
            throw new BaseException("内容不能为空");
        }
        if (reservationDto.getMobile().length() < 11) {
            throw new BaseException("手机号格式错误");
        }
        Long count = lambdaQuery().eq(Reservation::getMobile, reservationDto.getMobile()).eq(Reservation::getTime, reservationDto.getTime()).eq(Reservation::getStatus, 0).count();
        if (count > 0) {
            throw new BaseException("此手机号已预约该时间");
        }
        count = checkInService.lambdaQuery().eq(CheckIn::getElderName, reservationDto.getVisitor()).eq(CheckIn::getStatus, 1).count();
        if (count > 0) {
            throw new BaseException("已退住，不可预约");
        }
        BeanUtil.copyProperties(reservationDto, reservation);

        if (reservation.getType() == 0) {
            reservation.setStatus(0);
        }
        Long userId = UserThreadLocal.getUserId();
        save(reservation);
    }

    /**
     * 分页查询
     */
    @Override
    public TableDataInfo selectReservationList(ReservationPageDto reservationDto) {
        Page<Reservation> page = new Page<>(reservationDto.getPageNum(), reservationDto.getPageSize());
        LambdaQueryWrapper<Reservation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (reservationDto.getStatus() != null) {
            lambdaQueryWrapper.eq(Reservation::getStatus, reservationDto.getStatus()).eq(Reservation::getCreateBy, UserThreadLocal.getUserId());
        }
        //分页查询
        page = page(page, lambdaQueryWrapper);
        return getTableDataInfo(page);
    }

    private TableDataInfo getTableDataInfo(Page<Reservation> page) {
        TableDataInfo tableData = new TableDataInfo();
        tableData.setCode(HttpStatus.SUCCESS);
        tableData.setMsg("请求成功");
        tableData.setRows(page.getRecords());
        tableData.setTotal(page.getTotal());
        return tableData;
    }

    /**
     * 取消预约
     */
    @Override
    public void updateCancelStatus(Long id) {
        Reservation reservation = lambdaQuery().eq(Reservation::getId, id).one();
        reservation.setStatus(2);
        updateById(reservation);
    }

    /**
     * 定时更新预约状态
     */
    @Override
    public void updateReservationStatus() {
        List<Reservation> list = lambdaQuery().eq(Reservation::getStatus, 0).list();
        if (list.isEmpty()) {
            return;
        }
        list.forEach(reservation -> {
            String time = reservation.getTime();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            if (LocalDateTime.now().isAfter(LocalDateTime.parse(time, formatter))) {
                lambdaUpdate().eq(Reservation::getId, reservation.getId()).set(Reservation::getStatus, 1).update();
            }
        });
    }

    /**
     * 清理前十五天预约
     */
    @Override
    @Transactional
    public void clearReservation() {
        long time = System.currentTimeMillis();
        LocalDateTime ldt = LocalDateTimeUtil.of(time);
        LocalDateTime startTime = ldt.toLocalDate().atStartOfDay();
        startTime = startTime.minusDays(15);
        LocalDateTime endTime = startTime.plusDays(1);
        List<Reservation> list = lambdaQuery().between(Reservation::getTime, startTime, endTime).list();
        if (list.isEmpty()) {
            return;
        }
        removeBatchByIds(list);
    }
}
